package com.hongshu.web.service.recommendation;

import com.hongshu.web.service.recommendation.model.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 机器学习排序服务
 * 实现CTR预估、时长预估、互动率预估等排序算法
 *
 * @author hongshu
 * @date 2024/01/01
 */
@Service
@Slf4j
public class RankingService {

    @Autowired
    private FeatureEngineering featureEngineering;

    @Autowired
    private MLModelService mlModelService;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 机器学习排序主入口
     */
    public List<RankingItem> rankItems(List<String> candidateItems,
                                       UserProfile userProfile,
                                       RecommendContext context) {
        try {
            log.info("开始机器学习排序，候选物品数量: {}", candidateItems.size());
            // 1. 特征工程
            List<FeatureVector> features = featureEngineering
                    .extractFeatures(candidateItems, userProfile, context);
            // 2. 模型预测
            List<ModelPrediction> predictions = mlModelService
                    .batchPredict(features);
            // 3. 构建排序结果
            List<RankingItem> rankingItems = new ArrayList<>();
            for (int i = 0; i < candidateItems.size(); i++) {
                String itemId = candidateItems.get(i);
                ModelPrediction prediction = predictions.get(i);

                RankingItem rankingItem = RankingItem.builder()
                        .itemId(itemId)
                        .ctrScore(prediction.getCtrScore())
                        .durationScore(prediction.getDurationScore())
                        .interactionScore(prediction.getInteractionScore())
                        .finalScore(calculateFinalScore(prediction))
                        .build();

                rankingItems.add(rankingItem);
            }
            // 4. 按最终分数排序
            rankingItems.sort((a, b) -> Double.compare(b.getFinalScore(), a.getFinalScore()));
            log.info("机器学习排序完成，排序后物品数量: {}", rankingItems.size());
            return rankingItems;
        } catch (Exception e) {
            log.error("机器学习排序异常", e);
            // 降级到简单排序
            return fallbackRanking(candidateItems, userProfile);
        }
    }

    /**
     * 计算最终排序分数
     */
    private double calculateFinalScore(ModelPrediction prediction) {
        // 加权组合多个预测分数
        double ctrWeight = 0.4;      // CTR权重
        double durationWeight = 0.3; // 时长权重
        double interactionWeight = 0.3; // 互动权重

        return ctrWeight * prediction.getCtrScore() +
                durationWeight * prediction.getDurationScore() +
                interactionWeight * prediction.getInteractionScore();
    }

    /**
     * 降级排序策略
     */
    private List<RankingItem> fallbackRanking(List<String> candidateItems, UserProfile userProfile) {
        log.info("使用降级排序策略");
        List<RankingItem> rankingItems = new ArrayList<>();
        for (String itemId : candidateItems) {
            // 使用简单的启发式规则
            double score = calculateFallbackScore(itemId, userProfile);
            RankingItem rankingItem = RankingItem.builder()
                    .itemId(itemId)
                    .ctrScore(score)
                    .durationScore(score)
                    .interactionScore(score)
                    .finalScore(score)
                    .build();
            rankingItems.add(rankingItem);
        }
        rankingItems.sort((a, b) -> Double.compare(b.getFinalScore(), a.getFinalScore()));
        return rankingItems;
    }

    /**
     * 计算降级分数
     */
    private double calculateFallbackScore(String itemId, UserProfile userProfile) {
        try {
            // 1. 基础分数
            double baseScore = 0.5;
            // 2. 热度分数
            Double popularityScore = getItemPopularity(itemId);
            if (popularityScore != null) {
                baseScore += popularityScore * 0.3;
            }
            // 3. 用户兴趣匹配分数
            double interestScore = calculateInterestMatch(itemId, userProfile);
            baseScore += interestScore * 0.2;
            return Math.min(baseScore, 1.0); // 限制在[0,1]范围内
        } catch (Exception e) {
            log.error("计算降级分数异常", e);
            return 0.5;
        }
    }

    /**
     * 获取物品热度分数
     */
    private Double getItemPopularity(String itemId) {
        String key = "item_popularity:" + itemId;
        return (Double) redisTemplate.opsForValue().get(key);
    }

    /**
     * 计算兴趣匹配分数
     */
    private double calculateInterestMatch(String itemId, UserProfile userProfile) {
        try {
            // 获取物品标签
            List<String> itemTags = getItemTags(itemId);
            if (itemTags.isEmpty()) {
                return 0.0;
            }
            // 计算标签匹配度
            Map<String, Double> userTagPreferences = userProfile.getTagPreferences();
            double totalScore = 0.0;
            int matchCount = 0;
            for (String tag : itemTags) {
                Double preference = userTagPreferences.get(tag);
                if (preference != null) {
                    totalScore += preference;
                    matchCount++;
                }
            }
            return matchCount > 0 ? totalScore / matchCount : 0.0;
        } catch (Exception e) {
            log.error("计算兴趣匹配分数异常", e);
            return 0.0;
        }
    }

    /**
     * 获取物品标签
     */
    private List<String> getItemTags(String itemId) {
        String key = "item_tags:" + itemId;
        @SuppressWarnings("unchecked")
        List<String> tags = (List<String>) redisTemplate.opsForValue().get(key);
        return tags != null ? tags : new ArrayList<>();
    }

    /**
     * 特征工程服务
     */
    @Service
    public static class FeatureEngineering {

        @Autowired
        private RedisTemplate<String, Object> redisTemplate;


        /**
         * 提取特征向量
         */
        public List<FeatureVector> extractFeatures(List<String> candidateItems,
                                                   UserProfile userProfile,
                                                   RecommendContext context) {
            List<FeatureVector> features = new ArrayList<>();
            for (String itemId : candidateItems) {
                FeatureVector featureVector = extractItemFeatures(itemId, userProfile, context);
                features.add(featureVector);
            }
            return features;
        }

        /**
         * 提取单个物品的特征向量
         */
        private FeatureVector extractItemFeatures(String itemId,
                                                  UserProfile userProfile,
                                                  RecommendContext context) {
            // 1. 用户特征
            String userId = userProfile.getUserId();
            Integer userAge = userProfile.getAge();
            String userGender = userProfile.getGender();
            int userBehaviorCount = userProfile.getBehaviorCount();
            int userInterestCount = userProfile.getInterestTags().size();
            // 2. 物品特征
            ItemFeatures itemFeatures = getItemFeatures(itemId);
            double itemPopularity = itemFeatures.getPopularity();
            String itemCategory = itemFeatures.getCategory();
            int itemTagCount = itemFeatures.getTagCount();
            double itemAuthorPopularity = itemFeatures.getAuthorPopularity();
            long itemCreateTime = itemFeatures.getCreateTime();
            // 3. 上下文特征
            int currentHour = context.getCurrentHour();
            int currentDayOfWeek = context.getCurrentDayOfWeek();
            long currentPage = context.getCurrentPage();
            long pageSize = context.getPageSize();
            // 4. 交互特征
            InteractionFeatures interactionFeatures = getInteractionFeatures(itemId, userProfile.getUserId());
            int userItemInteractionCount = interactionFeatures.getInteractionCount();
            int userItemLikeCount = interactionFeatures.getLikeCount();
            int userItemCommentCount = interactionFeatures.getCommentCount();
            int userItemShareCount = interactionFeatures.getShareCount();
            // 创建 FeatureVector 对象
            return FeatureVector.builder()
                    .userId(userId)
                    .userAge(userAge)
                    .userGender(userGender)
                    .userBehaviorCount(userBehaviorCount)
                    .userInterestCount(userInterestCount)
                    .itemId(itemId)
                    .itemPopularity(itemPopularity)
                    .itemCategory(itemCategory)
                    .itemTagCount(itemTagCount)
                    .itemAuthorPopularity(itemAuthorPopularity)
                    .itemCreateTime(itemCreateTime)
                    .currentHour(currentHour)
                    .currentDayOfWeek(currentDayOfWeek)
                    .currentPage(currentPage)
                    .pageSize(pageSize)
                    .userItemInteractionCount(userItemInteractionCount)
                    .userItemLikeCount(userItemLikeCount)
                    .userItemCommentCount(userItemCommentCount)
                    .userItemShareCount(userItemShareCount)
                    .build();
        }

        /**
         * 获取物品特征
         */
        private ItemFeatures getItemFeatures(String itemId) {
            String key = "item_features:" + itemId;
            @SuppressWarnings("unchecked")
            Map<String, Object> features = (Map<String, Object>) redisTemplate.opsForValue().get(key);

            if (features == null) {
                return ItemFeatures.defaultFeatures();
            }

            return ItemFeatures.builder()
                    .popularity((Double) features.getOrDefault("popularity", 0.0))
                    .category((String) features.getOrDefault("category", "unknown"))
                    .tagCount((Integer) features.getOrDefault("tagCount", 0))
                    .authorPopularity((Double) features.getOrDefault("authorPopularity", 0.0))
                    .createTime((Long) features.getOrDefault("createTime", System.currentTimeMillis()))
                    .build();
        }

        /**
         * 获取交互特征
         */
        private InteractionFeatures getInteractionFeatures(String itemId, String userId) {
            String key = "user_item_interaction:" + userId + ":" + itemId;
            @SuppressWarnings("unchecked")
            Map<String, Object> interactions = (Map<String, Object>) redisTemplate.opsForValue().get(key);

            if (interactions == null) {
                return InteractionFeatures.defaultFeatures();
            }

            return InteractionFeatures.builder()
                    .interactionCount((Integer) interactions.getOrDefault("interactionCount", 0))
                    .likeCount((Integer) interactions.getOrDefault("likeCount", 0))
                    .commentCount((Integer) interactions.getOrDefault("commentCount", 0))
                    .shareCount((Integer) interactions.getOrDefault("shareCount", 0))
                    .build();
        }
    }

    /**
     * 机器学习模型服务
     */
    @Service
    public static class MLModelService {

        @Autowired
        private RedisTemplate<String, Object> redisTemplate;

        /**
         * 批量预测
         */
        public List<ModelPrediction> batchPredict(List<FeatureVector> features) {
            List<ModelPrediction> predictions = new ArrayList<>();

            for (FeatureVector feature : features) {
                ModelPrediction prediction = predict(feature);
                predictions.add(prediction);
            }

            return predictions;
        }

        /**
         * 单个预测
         */
        private ModelPrediction predict(FeatureVector feature) {
            try {
                // 1. CTR预测
                double ctrScore = predictCTR(feature);

                // 2. 时长预测
                double durationScore = predictDuration(feature);

                // 3. 互动率预测
                double interactionScore = predictInteraction(feature);

                return ModelPrediction.builder()
                        .ctrScore(ctrScore)
                        .durationScore(durationScore)
                        .interactionScore(interactionScore)
                        .build();

            } catch (Exception e) {
                log.error("模型预测异常", e);
                return ModelPrediction.defaultPrediction();
            }
        }

        /**
         * CTR预测（点击率预估）
         */
        private double predictCTR(FeatureVector feature) {
            // 简化的CTR预测逻辑
            double baseCTR = 0.1; // 基础CTR

            // 用户特征影响
            if (feature.getUserBehaviorCount() > 100) {
                baseCTR += 0.05; // 活跃用户CTR更高
            }

            // 物品特征影响
            if (feature.getItemPopularity() > 0.8) {
                baseCTR += 0.1; // 热门物品CTR更高
            }

            // 时间特征影响
            if (feature.getCurrentHour() >= 19 && feature.getCurrentHour() <= 22) {
                baseCTR += 0.05; // 晚上时段CTR更高
            }

            return Math.min(baseCTR, 0.5); // 限制在合理范围内
        }

        /**
         * 时长预测
         */
        private double predictDuration(FeatureVector feature) {
            // 简化的时长预测逻辑
            double baseDuration = 0.3; // 基础时长分数
            // 物品特征影响
            if (feature.getItemTagCount() > 5) {
                baseDuration += 0.2; // 标签多的内容时长更长
            }
            // 用户特征影响
            if (feature.getUserInterestCount() > 10) {
                baseDuration += 0.1; // 兴趣广泛的用户时长更长
            }
            return Math.min(baseDuration, 1.0);
        }

        /**
         * 互动率预测
         */
        private double predictInteraction(FeatureVector feature) {
            // 简化的互动率预测逻辑
            double baseInteraction = 0.2; // 基础互动率
            // 历史交互影响
            if (feature.getUserItemInteractionCount() > 0) {
                baseInteraction += 0.3; // 有历史交互的用户互动率更高
            }
            // 物品特征影响
            if (feature.getItemAuthorPopularity() > 0.7) {
                baseInteraction += 0.2; // 知名作者的内容互动率更高
            }
            return Math.min(baseInteraction, 0.8);
        }
    }

    // 内部数据类
    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public static class ItemFeatures {
        private double popularity;
        private String category;
        private int tagCount;
        private double authorPopularity;
        private long createTime;

        public static ItemFeatures defaultFeatures() {
            return ItemFeatures.builder()
                    .popularity(0.0)
                    .category("unknown")
                    .tagCount(0)
                    .authorPopularity(0.0)
                    .createTime(System.currentTimeMillis())
                    .build();
        }
    }

    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public static class InteractionFeatures {
        private int interactionCount;
        private int likeCount;
        private int commentCount;
        private int shareCount;

        public static InteractionFeatures defaultFeatures() {
            return InteractionFeatures.builder()
                    .interactionCount(0)
                    .likeCount(0)
                    .commentCount(0)
                    .shareCount(0)
                    .build();
        }
    }
}


